﻿using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using HuaXianQu.ProtoBuffEx.Runtime;
using UnityEditor;
using UnityEngine;
using Debug = UnityEngine.Debug;

namespace HuaXianQu.ProtoBuffEx.ToolEditor
{
    public class ProtoTool
    {

       public string ProtoProcessPath { get; set; }= Path.GetFullPath($"{Application.dataPath}/../Temp/protoc.exe");
       public virtual string ProtoDir { get;  set;}
       public virtual string GenerateProtoCsRootPath { get;set; }

       public List<string> Proto_Paths { get; set; }

       /// <summary>
        /// proto文件生成cs文件
        /// </summary>
        /// <returns></returns>
        public bool GenProtoToCsFile()
        {
            string protoDir = ProtoDir;
            protoDir = Path.GetFullPath(protoDir);
            if (!Directory.Exists(protoDir))
            {
                ProtoDebug.LogError($"{protoDir}未发现proto文件");
                return false;
            }


            DirectoryInfo folder = new DirectoryInfo(protoDir); // Proto所在路径
            FileInfo[] files = folder.GetFiles("*.proto", SearchOption.AllDirectories);
            if (files.Length == 0)
            {
                EditorUtility.DisplayDialog("ProtobuffToCSharpTool", @$"{protoDir}未发现proto文件", "OK");
                return false;
            }
#if UNITY_EDITOR_WIN
            string protogen = ProtoProcessPath;
            if (ProtoPathConfig.CurProtoPathConfig is DefaultIProtoPathConfig)
            {
                if (!File.Exists(protogen))
                {
                    string dirPath = Path.GetDirectoryName(protogen);
                    if (!Directory.Exists(dirPath))
                    {
                        Directory.CreateDirectory(dirPath);
                    }
                    File.Copy(ProtoPathConfig.Inst.ProtocPath, protogen);
                }
            }


#else
             string protogen = Path.GetFullPath(ProtoPathConfig.Inst.ProtocPath);
#endif


            if (!File.Exists(protogen))
            {
                EditorUtility.DisplayDialog("ProtobuffToCSharpTool",
                    @$"当前protoc路径：{protogen}错误。如果你重写DefaultIProtoPathConfig.自定义工具配置。请查看自定义ProtocPath属性的路径设置是否正确。请设置protoc程序的真实路径。",
                    "OK");
                return false;
            }

            if (Path.GetFileNameWithoutExtension(protogen) != "protoc")
            {
                EditorUtility.DisplayDialog("ProtobuffToCSharpTool", @"编译程序必须名称必须是“protoc”", "OK");
                return false;
            }
            

            string outDir = Path.GetFullPath($"{GenerateProtoCsRootPath}/ProtoGen");
            ClearFile(outDir);
            if (!Directory.Exists(outDir)) // CSharp 输出路径
            {
                Directory.CreateDirectory(outDir);
            }

            List<string> protoFiles = GetFiles(protoDir, files);
      

            GenerateCSharpCodeAll(protogen, outDir, Proto_Paths, protoFiles);
            //GenerateCSharpCode(protogen,outDir, proto_paths, protoFiles);
            return true;
        }

        private List<string> GetFiles(string protoDir, FileInfo[] files)
        {
            List<string> protoFiles = new List<string>();
            foreach (FileInfo file in files)
            {
                Debug.Assert(file.FullName != null, "file.DirectoryName != null");
                string filePath = file.FullName.Substring(protoDir.Length + 1).Replace("\\", "/");
                protoFiles.Add(filePath);
            }

            return protoFiles;
        }

        private void ClearFile(string path)
        {
            if (ProtoPathConfig.Inst.IsUsedDLL)
            {
                if (Directory.Exists(path))
                {
                    Directory.Delete(path, true);
                }
            }
            else
            {
                if (Directory.Exists(path))
                {
                    string[] files = Directory.GetFiles(path, "*.cs", SearchOption.AllDirectories);
                    foreach (string file in files)
                    {
                        File.Delete(file);
                    }
                    // string[] dirs =   Directory.GetDirectories(path, "*", SearchOption.AllDirectories);
                    // foreach (string dir in dirs)
                    // {
                    //     dir
                    // }
                }
            }
        }

        public void GenerateCSharpCodeAll(string processPath, string outputDir, List<string> protoDirs,
            List<string> protoPaths)
        {
            // 构造命令 所有文件使用一个指令（由于冲突放弃使用）
            string command =
                $"--csharp_out=\"{outputDir}\"  --proto_path={string.Join(" --proto_path=", protoDirs)} --csharp_opt=file_extension=.origin.cs,serializable \"{string.Join("\" \"", protoPaths)}\"";
            // 设置进程启动信息
            ProcessStartInfo startInfo = new ProcessStartInfo()
            {
                FileName = processPath, // 执行 protoc.exe
                Arguments = command, // 参数
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                UseShellExecute = false, // 不使用操作系统的 shell
                CreateNoWindow = true, // 不创建新窗口
                WorkingDirectory = ".",
            };
            // 启动进程
            Process process = new Process();
            process.StartInfo = startInfo;
            // process.OutputDataReceived += OutputHandler;
            // process.ErrorDataReceived += ErrorDataHandler;

            process.Start();
            // 获取并显示输出
            string output = process.StandardOutput.ReadToEnd();
            string error = process.StandardError.ReadToEnd();

            process.WaitForExit();

            // 显示结果
            if (!string.IsNullOrEmpty(output))
            {
                ProtoDebug.Log("Output: " + output);
            }

            if (!string.IsNullOrEmpty(error))
            {
                ProtoDebug.LogError("Error: " + error);
            }
        }

        public void GenerateCSharpCode(string processPath, string outputDir, List<string> proto_paths,
            List<string> protoPaths)
        {
            // 设置进程启动信息
            ProcessStartInfo startInfo = new ProcessStartInfo()
            {
                FileName = processPath, // 执行 protoc.exe
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                UseShellExecute = false, // 不使用操作系统的 shell
                CreateNoWindow = true, // 不创建新窗口
                WorkingDirectory = ".",
            };
            // 启动进程
            Process process = new Process();
            process.StartInfo = startInfo;
            string commandRoot =
                $"--csharp_out=\"{outputDir}\"  --proto_path={string.Join(" --proto_path=", proto_paths)} --csharp_opt=file_extension=.origin.cs,serializable";

            for (int i = 0; i < protoPaths.Count; i++)
            {
                string command = $"{commandRoot} \"{protoPaths[i]}\"";
                startInfo.Arguments = command;
                process.Start();
                // 获取并显示输出
                string output = process.StandardOutput.ReadToEnd();
                string error = process.StandardError.ReadToEnd();

                process.WaitForExit();

                // 显示结果
                if (!string.IsNullOrEmpty(output))
                {
                    ProtoDebug.Log("Output: " + output);
                }

                if (!string.IsNullOrEmpty(error))
                {
                    if ((error.Contains("Import Config/ConvetConfig.proto is unused") ||
                         error.Contains(
                             "Import Client/ExcelVariableAttribute.proto is unused")))
                    {
                        continue;
                    }

                    ProtoDebug.LogError(
                        $"请查看Excel的字段配置是否正确，路径下：{ProtoPathConfig.Inst.GenerateProtoPath}生成proto文件异常 Error: " + error);
                }
            }
        }

        private void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
        {
            if (!string.IsNullOrEmpty(outLine.Data))
            {
                ProtoDebug.Log(outLine.Data);
            }
        }

        private void ErrorDataHandler(object sendingProcess, DataReceivedEventArgs outLine)
        {
            if (!string.IsNullOrEmpty(outLine.Data))
            {
                if (outLine.Data is string str && (str.Contains("Import Config/ConvetConfig.proto is unused") ||
                                                   str.Contains(
                                                       "Import Client/ExcelVariableAttribute.proto is unused")))
                {
                    return;
                }

                ProtoDebug.LogError(outLine.Data);
            }
        }
    }
}